package com.sudoku.board;

import java.util.ArrayList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.sudoku.observer.Event;
import com.sudoku.observer.Subject;
import com.sudoku.utility.Constants;
import com.sudoku.utility.Locator;

public class Tile implements Constants {

	private Vector2 coords;
	private char data;
	private Color color;
	private boolean permanent;
	private ArrayList<Integer> pencilNumbers;
	private float pencilSpacingX, pencilSpacingY;
	private boolean wrong;
	private boolean flashing;
	private float wrongTimer;
	private Subject subject;
	private Color white = new Color(1, 1, 1, 1);
	//private Color red = new Color(1, 0, 0, 1);
	private Box box;
	private Color flashColor;

	public Tile(Box box, Vector2 coords, char data, Subject subject) {
		this.coords = coords;
		this.subject = subject;
		this.data = data;
		this.box = box;
		this.color = new Color(Color.WHITE);
		pencilNumbers = new ArrayList<Integer>();
		permanent = false;
		wrongTimer = 0;
		wrong = false;
		flashing = true;
		flashColor=new Color(Color.WHITE);

		pencilSpacingX = TILE_PIXEL_SIZE / 3;
		pencilSpacingY = TILE_PIXEL_SIZE / 3;
	}

	public void render(SpriteBatch sb, BitmapFont font, BitmapFont pencilFont, ShapeRenderer sr) {
		Gdx.gl.glEnable(GL20.GL_BLEND);
		Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
		sr.begin(ShapeType.Filled);
		Color newColor = new Color(color);
		if (permanent) {
			newColor.sub(0.1f, 0.1f, 0.1f, -0.1f);
		}
		sr.setColor(newColor);
		sr.rect(getXPosition(), getYPosition(), TILE_PIXEL_SIZE, TILE_PIXEL_SIZE);
		sr.end();
		Gdx.gl.glDisable(GL20.GL_BLEND);

		sb.begin();
		if (data != ' ') {
			font.setColor(Color.BLACK);
			font.draw(sb, Character.toString(data), getXPosition() + TILE_PIXEL_SIZE / 2.6f, getYPosition() + TILE_PIXEL_SIZE / 1.4f);
		} else {
			for (Integer i : pencilNumbers) {
				int row = ((i - 1) / 3) % 3;
				pencilFont.draw(sb, "" + i, getXPosition() + pencilSpacingX * ((i - 1) % 3) + TILE_PIXEL_SIZE * 0.1f, getYPosition()
						+ TILE_PIXEL_SIZE * 0.95f - pencilSpacingY * row);
			}
		}
		sb.end();

		update(Gdx.graphics.getDeltaTime());
	}

	public void update(float delta) {
		// flash red when it contains the wrong answer
		if (wrong) {
			wrongTimer += delta;
			if (flashing) {
				Color temp = new Color(white);
				temp = temp.lerp(flashColor, wrongTimer * 2);
				setColor(temp);
				if (wrongTimer > 0.5f) {
					wrongTimer = 0;
					flashing = false;
				}
			}
			if (!flashing) {
				Color temp = new Color(flashColor);
				temp = temp.lerp(white, wrongTimer * 2);
				setColor(temp);
				if (wrongTimer > 0.5f) {
					wrong = false;
					wrongTimer = 0;
					subject.notify(Event.EVENT_CHECK_DONE);
				}
			}

		}
	}

	public void addPencilNumber(int p) {
		if (!pencilNumbers.contains(p)) {
			pencilNumbers.add(p);
		}
	}

	public boolean removePencilNumber(Integer p) {
		return pencilNumbers.remove(p);
	}

	public void clearPencilNumbers() {
		pencilNumbers.clear();
	}

	public void setPermanent(boolean p) {
		permanent = p;
	}

	public Vector2 getCoords() {
		return coords;
	}

	public void setCoords(Vector2 coords) {
		this.coords = coords;
	}

	public void setPencilNumbers(ArrayList<Integer> pencilNumbers) {
		this.pencilNumbers = pencilNumbers;
	}

	public Color getColor() {
		return color;
	}

	public void setColor(Color color) {
		this.color = color;
	}

	public char getData() {
		return data;
	}

	public void setData(char data) {
		this.data = data;
	}

	public boolean isPermanent() {
		return permanent;
	}

	public void selected(boolean pencil) {
		if (!pencil) {
			// light blue
			setColor(new Color(0f, 0.0f, 1.0f, 0.4f));
		} else {
			// light green if pencil mode
			setColor(new Color(0f, 1f, 0f, 0.4f));
		}

	}

	public boolean containsPosition(float tempX, float tempY) {
		return ((tempX >= getXViewPosition()) && (tempY >= getYViewPosition()) && (tempX < getXViewPosition() + Locator.TILE_PIXEL_SIZE) && (tempY < getYViewPosition()
				+ Locator.TILE_PIXEL_SIZE));
	}

	public float getXPosition() {
		return box.getXPosition() + TILE_PIXEL_SIZE * (coords.x);
	}

	public float getYPosition() {
		return box.getYPosition() + TILE_PIXEL_SIZE * (coords.y);
	}

	public float getXViewPosition() {
		return box.getXViewPosition() + Locator.TILE_PIXEL_SIZE * (coords.x);
	}

	public float getYViewPosition() {
		return box.getYViewPosition() + Locator.TILE_PIXEL_SIZE * (coords.y);
	}

	public void unselect() {
		setColor(Color.WHITE);

	}

	public void unhover() {
		setColor(Color.WHITE);

	}

	public void highlight() {
		// light yellow
		setColor(new Color(1f, 1.0f, 0.0f, 0.4f));

	}

	public void hover() {
		// light gray
		setColor(new Color(0, 0, 0, 0.4f));

	}

	public boolean isBlank() {
		return data == ' ';
	}

	public ArrayList<Integer> getPencilNumbers() {
		return pencilNumbers;
	}

	public void flashWrong() {
		wrong = true;
		flashing = true;
		flashColor=Color.RED;
		setColor(Color.WHITE);
	}

	public Box getBox() {
		return box;
	}

	public void setBox(Box box) {
		this.box = box;
	}

	public void flashHint() {
		wrong = true;
		flashing = true;
		flashColor=Color.MAGENTA;
		setColor(Color.WHITE);
		
	}

	public void setBlank() {
		data=' ';
		clearPencilNumbers();
	}

}
